﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Newtonsoft.Json;
//using SevenZip;
using ICSharpCode.SharpZipLib.Checksum;

public class LangJson
{
    public string key;
    public string value;
}

public static class LangTool
{
    static string GenFilePath = "Assets/GenScript/TextKey.cs";
    static Dictionary<string, int> keyMap;
    static Dictionary<int, string> reverseKeyMap;

    [MenuItem("Custom/LangTool/Reset")]
    static void Reset()
    {
        keyMap = null;
        reverseKeyMap = null;
        UILabelExInspector.RefreshKeys();
    }

    public static Dictionary<string, int> GetKeyMap()
    {
        if (keyMap != null)
        {
            return keyMap;
        }

        keyMap = new Dictionary<string, int>();

        string keyStr = CommonUtil.fileToString(GenFilePath);
        if (keyStr != null)
        {
            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"(\w+)\s*=\s*(-?[0-9]+);");

            System.IO.StringReader reader = new System.IO.StringReader(keyStr);
            while (true)
            {
                string line = reader.ReadLine();
                if (string.IsNullOrEmpty(line))
                {
                    break;
                }

                System.Text.RegularExpressions.Match match = regex.Match(line);
                if (match.Groups.Count > 2)
                {
                    string varName = match.Groups[1].Value;
                    string crcStr = match.Groups[2].Value;
                    int crc = int.Parse(crcStr);
                    keyMap.Add(varName, crc);
                }
            }
        }

        return keyMap;
    }

    public static Dictionary<int, string> GetReverseKeyMap()
    {
        if (reverseKeyMap != null)
        {
            return reverseKeyMap;
        }

        GetKeyMap();
        reverseKeyMap = new Dictionary<int, string>();
        foreach(var entry in keyMap)
        {
            reverseKeyMap.Add(entry.Value, entry.Key);
        }
        return reverseKeyMap;
    }

    static int StringCRC(string str)
    {
        Crc32 crc32 = new Crc32();
        crc32.Update(System.Text.ASCIIEncoding.ASCII.GetBytes(str));
        return (int)(crc32.Value & 0xffffffff);
    }

    [MenuItem("Assets/Custom/LangTool/Convert")]
    public static void Convert ()
    {
        reverseKeyMap = null;
        keyMap = null;
        Dictionary<int, string> oldReverseKeyMap = GetReverseKeyMap();
//        Debug.LogError("old_keys_count: " + oldReverseKeyMap.Count);

        HashSet<int> newReverseKeySet = new HashSet<int>();

        EditorCommonTool.ProcessSelectionObjs("*.json", (path) =>
            {
                string str = CommonUtil.fileToString(path);
                Dictionary<string, LangJson> jsonMap = JsonConvert.DeserializeObject<Dictionary<string, LangJson>>(str);

                //check repeat
                if(true && System.IO.Path.GetFileNameWithoutExtension(path) == SystemLanguage.ChineseSimplified.ToString())
                {
                    Dictionary<string, HashSet<string>> repeatKeysMap =  new Dictionary<string, HashSet<string>>();
                    foreach(var entry in jsonMap)
                    {
                        HashSet<string> keySet = null;
                        if(!repeatKeysMap.TryGetValue(entry.Value.value, out keySet))
                        {
                            keySet = new HashSet<string>();
                            repeatKeysMap.Add(entry.Value.value, keySet);
                        }

                        keySet.Add(entry.Key);
                    }

                    string log = "";
                    Dictionary<string, HashSet<string>>.Enumerator e = repeatKeysMap.GetEnumerator();
                    while(e.MoveNext())
                    {
                        if(e.Current.Value.Count > 1)
                        {
                            log += "repeat content: " + @"""" + e.Current.Key + @"""" + "  |  (";
                            int c = 0;
                            foreach(var key in e.Current.Value)
                            {
                                c++;
                                if(c == e.Current.Value.Count)
                                {
                                    log += key;
                                }
                                else
                                {
                                    log += key + ",";
                                }
                                
                            }

                            log += ")\n";
                        }
                    }
                    
                    if(!string.IsNullOrEmpty(log))
                    {
                        CommonUtil.stringToFile(System.IO.Path.ChangeExtension(CommonUtil.addSuffixToFileName(path, "repeat_content"), ".txt"), log);
//                        return;
                    }
                }

                foreach(var entry in jsonMap)
                {
                    int crc = StringCRC(entry.Key);

                    string temp = null;
                    if(oldReverseKeyMap.TryGetValue(crc, out temp))
                    {
                        if(temp != entry.Key)
                        {
                            while(true)
                            {
                                string newKey = entry.Key + "_" + entry.Key.GetHashCode() + "_" + Random.Range(0, 100000);
                                crc = StringCRC(newKey);
                                if(!oldReverseKeyMap.TryGetValue(crc, out temp))
                                {
                                    newReverseKeySet.Add(crc);
                                    oldReverseKeyMap.Add(crc, entry.Key);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            newReverseKeySet.Add(crc);
                        }
                    }
                    else
                    {
                        newReverseKeySet.Add(crc);
                        oldReverseKeyMap.Add(crc, entry.Key);
                    }
                }
            });

        if (newReverseKeySet.Count <= 0)
        {
            return;
        }

//        Dictionary<int, string>.KeyCollection keys = oldReverseKeyMap.Keys;
        List<int> keys = new List<int>(oldReverseKeyMap.Keys);
        foreach (var key in keys)
        {
            if (!newReverseKeySet.Contains(key))
            {
                oldReverseKeyMap.Remove(key);
            }
        }

        Dictionary<string, int> newKeyMap = new Dictionary<string, int>();
        foreach (var entry in oldReverseKeyMap)
        {
            newKeyMap.Add(entry.Value, entry.Key);
        }

        string codeStr = "public static class TextKey\n{";
        foreach (var entry in oldReverseKeyMap)
        {
            codeStr += "\n\tpublic const int " + entry.Value + " = " + entry.Key + ";";
        }
        codeStr += "\n}";

        string dirPath = System.IO.Path.GetDirectoryName(GenFilePath);
        CommonUtil.CreateDir(dirPath);
        CommonUtil.stringToFile(GenFilePath, codeStr);

        EditorCommonTool.ProcessSelectionObjs("*.json", (path) =>
            {
                string str = CommonUtil.fileToString(path);
                Dictionary<string, LangJson> jsonMap = JsonConvert.DeserializeObject<Dictionary<string, LangJson>>(str);
                LangConfig langConfig = new LangConfig();
                langConfig.intKeyToLangMap = new Dictionary<int, string>();
                foreach(var entry in jsonMap)
                {
//                    if(!newKeyMap.ContainsKey(entry.Key))
//                    {
//                        Debug.LogError("adf: " + entry.Key + "  " + entry.Value.value + "  " + entry.Value.key);
//                    }
                    langConfig.intKeyToLangMap.Add(newKeyMap[entry.Key], entry.Value.value);
                }
                langConfig.stringKeyToIntKeyMap = newKeyMap;

                string newStr = JsonConvert.SerializeObject(langConfig, Formatting.Indented);
                CommonUtil.stringToFile(System.IO.Path.ChangeExtension(path, ".txt"), newStr);
                CommonUtil.Delete(path);
            });

        Reset();
        AssetDatabase.Refresh();
	}

//    [MenuItem("Custom/LangTool/ExportAllTextToCSV")]
//    public static void ExportAllTextToCSV ()
//    {
//        string[] paths = System.IO.Directory.GetFiles(ResourcesEx.BundleResDir + "/", "*.prefab", System.IO.SearchOption.AllDirectories);
//        string str = CommonUtil.fileToString(ResourcesEx.BundleResDir + "/lang/ChineseSimplified.txt");
//        Dictionary<int, string> textMaps = JsonConvert.DeserializeObject<Dictionary<int, string>>(str);
//        Dictionary<int, string>.ValueCollection texts = textMaps.Values;
//        string[] strings = new string[texts.Count];
//        texts.CopyTo(strings, 0);
//
//        System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[\u4e00-\u9fa5]+");
//
//        string content = "";
//        HashSet<string> addedTextSet = new HashSet<string>();
//        for (int i = 0; i < paths.Length; i++)
//        {
//            GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(paths[i]);
//            UILabelEx[] labels = prefab.GetComponentsInChildren<UILabelEx>();
//            for (int j = 0; j < labels.Length; j++)
//            {
//                UILabelEx label = labels[j];
//                if (label.textKey == 0)
//                {
//                    string text = label.text;
//                    if (!string.IsNullOrEmpty(text) && !addedTextSet.Contains(text) && System.Array.FindIndex(strings, (a) => {return a == text;}) < 0 && regex.IsMatch(text))
//                    {
//                        content += text + "\n";
//                        addedTextSet.Add(text);
//                    }
//                }
//            }
//        }
//
//        CommonUtil.stringToFile("Assets/text.csv", content);
//        AssetDatabase.Refresh();
//    }

    public static void ConvertToTextKey(GameObject prefab, Dictionary<string, int> reverseMap, Dictionary<int, string> intKeyStringKeyMap, HashSet<string> errorTextSet)
    {
        UILabelEx[] labels = prefab.GetComponentsInChildren<UILabelEx>(true);
        bool modified = false;
        for (int j = 0; j < labels.Length; j++)
        {
            UILabelEx label = labels[j];
            if (label.textKey == 0)
            {
                string text = label.text;
                int key = 0;
                if (reverseMap.TryGetValue(text, out key))
                {
                    if (replace)
                    {
                        modified = true;
                        label.SetTextKeyName(key, intKeyStringKeyMap[key]);
                    }
                }
                else if (!string.IsNullOrEmpty(text) && !errorTextSet.Contains(text) && chineseRegex.IsMatch(text))
                {
                    errorTextSet.Add(text);
                }
            }
        }

        if (modified)
        {
            GameObject prefabObj = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
            PrefabUtility.ReplacePrefab(prefabObj, prefab, ReplacePrefabOptions.Default);
            GameObject.DestroyImmediate(prefabObj);
        }
    }

    static bool replace = true;
    static System.Text.RegularExpressions.Regex chineseRegex = new System.Text.RegularExpressions.Regex(@"[\u4e00-\u9fa5]+");

    [MenuItem("Assets/Custom/LangTool/ConvertToTextKey")]
    public static void ConvertToTextKeyForSelection ()
    {
        Dictionary<int, string> intKeyStringKeyMap = GetReverseKeyMap();
        LangAllString allStrings = LangManager.LoadLang(SystemLanguage.ChineseSimplified);
        Dictionary<string, int> reverseMap = allStrings.GetReverseMap();


        HashSet<string> addedTextSet = new HashSet<string>();
        GameObject prefab = Selection.activeGameObject;
        ConvertToTextKey(prefab, reverseMap, intKeyStringKeyMap, addedTextSet);
    }

    [MenuItem("Custom/LangTool/ConvertToTextKey")]
    public static void ConvertToTextKey ()
    {
        Dictionary<int, string> intKeyStringKeyMap = GetReverseKeyMap();

        LangAllString allStrings = LangManager.LoadLang(SystemLanguage.ChineseSimplified);
        Dictionary<string, int> reverseMap = allStrings.GetReverseMap();


        HashSet<string> addedTextSet = new HashSet<string>();
        string[] paths = System.IO.Directory.GetFiles(ResourcesEx.BundleResDir + "/", "*.prefab", System.IO.SearchOption.AllDirectories);
        for (int i = 0; i < paths.Length; i++)
        {
            GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(paths[i]);
            ConvertToTextKey(prefab, reverseMap, intKeyStringKeyMap, addedTextSet);
        }



        string content = "";

        Dictionary<string, List<string>> foundCode = new Dictionary<string, List<string>>();
        System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@"(""[^""\n\r]*[\u4e00-\u9fa5]+[^""\n\r]*"")");
//        Debug.LogError(regex2.ToString());
        string[] codePaths = System.IO.Directory.GetFiles("Assets/LuaFramework/Lua", "*.lua", System.IO.SearchOption.AllDirectories);
        for (int i = 0; i < codePaths.Length; i++)
        {
            string codePath = codePaths[i];
            if (codePath.Contains("Assets/LuaFramework/Lua/config"))
            {
                continue;
            }

            string str = CommonUtil.fileToString(codePath);
            System.IO.StringReader reader = new System.IO.StringReader(str);
            int lineNum = 0;
            while (true)
            {
                string line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }

                int commetIndex = line.IndexOf("--");

                int logIndex = line.IndexOf("logError");
                if (logIndex < 0)
                {
                    logIndex = line.IndexOf("logWarn");
                }
                if (logIndex < 0)
                {
                    logIndex = line.IndexOf("log(");
                }
                if (logIndex < 0)
                {
                    logIndex = line.IndexOf("logException");
                }
                if (logIndex < 0)
                {
                    logIndex = line.IndexOf("logDbg");
                }


                lineNum++;
                System.Text.RegularExpressions.MatchCollection matches = regex2.Matches(line);
                for (int j = 0; j < matches.Count; j++)
                {
                    System.Text.RegularExpressions.Match match = matches[j];
                    if (commetIndex >= 0 && match.Index > commetIndex)
                    {
                        continue;
                    }

                    if (logIndex >= 0 && match.Index > logIndex)
                    {
                        continue;
                    }

                    string temp = match.Groups[1].Value;
                    List<string> foundFileLines = null;
                    if (!foundCode.TryGetValue(temp, out foundFileLines))
                    {
                        foundFileLines = new List<string>();
                        foundCode.Add(temp, foundFileLines);
                    }

                    foundFileLines.Add(codePath + ":" + lineNum + "       " + line);
                }
            }

        }

        string log = "";
        foreach (var entry in foundCode)
        {
            int key = 0;
            string temp = entry.Key.Substring(1, entry.Key.Length - 2);
            if (reverseMap.TryGetValue(temp, out key))
            {
                log += entry.Key + " (" + GetReverseKeyMap()[key] + "):\n";
            }
            else
            {
                log += entry.Key + ":\n";
                if(temp != null && !addedTextSet.Contains(temp))
                {
                    addedTextSet.Add(temp);
                }
            }

            foreach (var path in entry.Value)
            {
                log += "\t" + path + "\n";
            }
        }

        if (addedTextSet.Count > 0)
        {
            foreach (var key in addedTextSet)
            {
                content += key + "\n";
            }
            content = "not in multi lang: \n\n" + content;
        }

        if (!string.IsNullOrEmpty(log))
        {
            content += "\n\n\n\n\n\nnot in multi lang code string: \n\n" + log;
        }



        CommonUtil.stringToFile("Assets/text.txt", content);

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
}
